<!-- TextureにCubeのサンプルをレンダリングする -->
<html>
<head>
<!-- 行列演算用ライブラリ -->
<script src="CanvasMatrix.js" type="text/javascript"></script>

<!-- Cube用のシェーダー -->
<script id="vshader_cube" type="x-shader/x-vertex"> 
  attribute vec4 vPosition;
  attribute vec4 vTexCoord;
  varying vec2 texCoord;
  uniform mat4 projMat;
  void main()
  {
    gl_Position = projMat * vPosition;
    texCoord.xy = vTexCoord.xy;
  }
</script>
 
<script id="fshader_cube" type="x-shader/x-fragment"> 
#ifdef GL_ES
precision highp float;
#endif
  uniform sampler2D sampler2d;
  varying vec2 texCoord;
  void main()
  {
    gl_FragColor = texture2D(sampler2d, texCoord);
  }
</script>

<!-- 描画用のシェーダー -->
<script id="vshader_render" type="x-shader/x-vertex"> 
  attribute vec4 vPosition;
  attribute vec4 vTexCoord;
  varying vec2 texCoord;
  void main()
  {
    gl_Position = vPosition;
    texCoord.x = vTexCoord.x;
    texCoord.y = 1.0-vTexCoord.y;
  }
</script>

<script id="fshader_render" type="x-shader/x-fragment"> 
#ifdef GL_ES
precision highp float;
#endif
  uniform sampler2D sampler2d;
  varying vec2 texCoord;
  void main()
  {
    // ブラーっぽくレンダリング
    vec4 sample0, sample1, sample2, sample3;
    float step = 0.005;
    sample0 = texture2D(sampler2d, vec2(texCoord.x - step, texCoord.y - step));
    sample1 = texture2D(sampler2d, vec2(texCoord.x + step, texCoord.y + step));
    sample2 = texture2D(sampler2d, vec2(texCoord.x + step, texCoord.y - step));
    sample3 = texture2D(sampler2d, vec2(texCoord.x - step, texCoord.y + step));
    //gl_FragColor = (sample0 + sample1 + sample2 + sample3) / 4.0;
    
    // そのままレンダリング
    gl_FragColor = texture2D(sampler2d, texCoord);
  }
</script>

<script>
  var cvWidth = 0;
  var cvHeight = 0;
  var vertexBuffer;
  var indexBuffer;
  var vertint;
  var texint;
  var indint;
  var tex;
  var cubeShader;
  
  var render_vertint;
  var render_texint;
  var renderShader;
  var framebuffer;
  var renderbuffer;
  var rendertex;
  
  var curAngleX = 0;
  var curAngleY = 0;
  var camLength = 5;
  var setX = 0;
  var setY = 0;
  var buttonFlg = 0;
  function init(canvas)
  {
    var gl = canvas.getContext("experimental-webgl");
    if (!gl) {
      alert("Failed to create WebGL context.");
      return null;
    }
    
    // Cube用のシェーダをロード
    vshader_cube = gl.createProgram();
    {
      var vshaderScript = document.getElementById("vshader_cube");
      var fshaderScript = document.getElementById("fshader_cube");
      if (!vshaderScript) {
        alert("Failed to get vshaderScript.");
        return null;
      }
      if (!fshaderScript) {
        alert("Failed to get fshaderScript.");
        return null;
      }
      
      var vshader = gl.createShader(gl.VERTEX_SHADER);
      var fshader = gl.createShader(gl.FRAGMENT_SHADER);
      if (!vshader || !fshader) {
        alert("Failed to createShader().");
        return null;
      }
      
      gl.shaderSource(vshader, vshaderScript.text);
      gl.shaderSource(fshader, fshaderScript.text);
      
      gl.compileShader(vshader);
      gl.compileShader(fshader);
      
      gl.attachShader(vshader_cube, vshader);
      gl.attachShader(vshader_cube, fshader);
      
      gl.bindAttribLocation(vshader_cube, 0, "vPosition");
      gl.bindAttribLocation(vshader_cube, 1, "vTexCoord");
      
      gl.enableVertexAttribArray(0);  // vPosition
      gl.enableVertexAttribArray(1);  // vTexCoord
      
      gl.linkProgram(vshader_cube);
    }
    
    // 描画用のシェーダーをロード
    renderShader = gl.createProgram();
    {
      var vshaderScript = document.getElementById("vshader_render");
      var fshaderScript = document.getElementById("fshader_render");
      if (!vshaderScript) {
        alert("Failed to get vshaderScript.");
        return null;
      }
      if (!fshaderScript) {
        alert("Failed to get fshaderScript.");
        return null;
      }
      
      var vshader = gl.createShader(gl.VERTEX_SHADER);
      var fshader = gl.createShader(gl.FRAGMENT_SHADER);
      if (!vshader || !fshader) {
        alert("Failed to createShader().");
        return null;
      }
      
      gl.shaderSource(vshader, vshaderScript.text);
      gl.shaderSource(fshader, fshaderScript.text);
      
      gl.compileShader(vshader);
      gl.compileShader(fshader);
      
      gl.attachShader(renderShader, vshader);
      gl.attachShader(renderShader, fshader);
      
      gl.bindAttribLocation(renderShader, 0, "vPosition");
      gl.bindAttribLocation(renderShader, 1, "vTexCoord");
      
      gl.enableVertexAttribArray(0);  // vPosition
      gl.enableVertexAttribArray(1);  // vTexCoord
      
      gl.linkProgram(renderShader);
    }
    
    gl.clearColor(0, 0, 0, 1);
    gl.clearDepth(1000);
    
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    
    gl.enable(gl.TEXTURE_2D);
    tex = gl.createTexture();
    tex.image = new Image();
    tex.image.onload = function() { 
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tex.image);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.bindTexture(gl.TEXTURE_2D, null);	
    }
    tex.image.src = "img.jpg";
    
    // 頂点情報
    var vertices = [
       1,  1,  1,  -1,  1,  1,  -1, -1,  1,   1, -1,  1,
       1,  1,  1,   1, -1,  1,   1, -1, -1,   1,  1, -1,
       1,  1,  1,   1,  1, -1,  -1,  1, -1,  -1,  1,  1,
      -1,  1,  1,  -1,  1, -1,  -1, -1, -1,  -1, -1,  1,
      -1, -1, -1,   1, -1, -1,   1, -1,  1,  -1, -1,  1,
       1, -1, -1,  -1, -1, -1,  -1,  1, -1,   1,  1, -1 
    ];
    vertint = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertint);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    vertint.itemSize = 3;
    vertint.numItems = 24;
    
    // テクスチャ贀W情報
    var texcoords = [
      0, 0,   1, 0,   1, 1,   0, 1,
      1, 0,   1, 1,   0, 1,   0, 0,
      0, 1,   0, 0,   1, 0,   1, 1,
      0, 0,   1, 0,   1, 1,   0, 1,
      1, 1,   0, 1,   0, 0,   1, 0,
      1, 1,   0, 1,   0, 0,   1, 0 
    ];
    texint = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texint);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW);
    texint.itemSize = 2;
    texint.numItems = 24;
    
    // 頂点インデックス
    var indices = [
       0, 1, 2,   0, 2, 3,    // front
       4, 5, 6,   4, 6, 7,    // right
       8, 9,10,   8,10,11,    // top
      12,13,14,  12,14,15,    // left
      16,17,18,  16,18,19,    // bottom
      20,21,22,  20,22,23     // back
    ];
    idxint = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, idxint);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    idxint.itemSize = 3;
    idxint.numItems = indices.length;;
    
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    
    // フレームバッファオブジェクトを作成
    framebuffer  = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
    {
      framebuffer.width = cvWidth;
      framebuffer.height = cvHeight;
      rendertex = gl.createTexture();
      {
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, rendertex);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, cvWidth, cvHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rendertex, 0);
        // Cubeは奥行きがあるのでデプスバッファ用にレンダーバッファオブジェクトを作成
        renderbuffer = gl.createRenderbuffer();
        {
          gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
          gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, cvWidth, cvHeight);
          gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
          gl.bindRenderbuffer(gl.RENDERBUFFER, null);
        }
        gl.bindTexture(gl.TEXTURE_2D, null);
      }
      if (!gl.isFramebuffer(framebuffer)) {
        alert("Failed to create framebuffer object");
      } else {
        console.log("Success to create framebuffer object.");
      }
      var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
      if (status != gl.FRAMEBUFFER_COMPLETE) {
        console.log("status != gl.FRAMEBUFFER_COMPLETE");
      } else {
        console.log("status == gl.FRAMEBUFFER_COMPLETE");
      }
      
      gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    }
    
    {
      var vertices = [
        -1.0, +1.0,  0.0,
        +1.0, +1.0,  0.0,
        -1.0, -1.0,  0.0,
        +1.0, -1.0,  0.0,
      ];
      render_vertint = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, render_vertint);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
      render_vertint.itemSize = 3;
      render_vertint.numItems = 4;
      gl.bindBuffer(gl.ARRAY_BUFFER, null);
    }
    {
      var texcoords = [
        0, 0,
        1, 0,
        0, 1,
        1, 1,
      ];
      render_texint = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, render_texint);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW);
      render_texint.itemSize = 2;
      render_texint.numItems = 4;
      
      gl.bindBuffer(gl.ARRAY_BUFFER, null);
    }
    return gl;
  }
  
  function reshape(gl)
  {
    var canvas = document.getElementById("myCanvas");
    if (canvas.clientWidth == cvWidth
     && canvas.clientHeight == cvHeight) {
      return;
    }
    cvWidth = canvas.clientWidth;
    cvHeight = canvas.clientHeight;
    gl.viewport(0, 0, cvWidth, cvHeight);
  }
  
  function Render(gl)
  {
    reshape(gl);
    {
      gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
      gl.useProgram(vshader_cube);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      gl.clearDepth(1.0);
      
      var cameraMat = new CanvasMatrix4();
      cameraMat.makeIdentity();
      cameraMat.lookat(
        0.0, 0.0, camLength,
        0.0, 0.0, 0.0,
        0.0, 1.0, 0.0);
      cameraMat.perspective(40, cvWidth/cvHeight, 1, 1000);
      
      var modelMat = new CanvasMatrix4();
      modelMat.makeIdentity();
      modelMat.rotate(curAngleX, 1,0,0);
      modelMat.rotate(curAngleY, 0,1,0);
      modelMat.multRight(cameraMat);
      gl.uniformMatrix4fv(
        gl.getUniformLocation(vshader_cube, "projMat"),
        false,
        modelMat.getAsFloat32Array());
      
      gl.bindBuffer(gl.ARRAY_BUFFER, vertint);
      gl.vertexAttribPointer(0, vertint.itemSize, gl.FLOAT, false, 0, 0);
      
      gl.bindBuffer(gl.ARRAY_BUFFER, texint);
      gl.vertexAttribPointer(1, texint.itemSize, gl.FLOAT, false, 0, 0);
      
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, idxint);
      
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.drawElements(gl.TRIANGLES, idxint.numItems, gl.UNSIGNED_SHORT, 0);
      gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    }
    
    gl.useProgram(renderShader);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.clearDepth(1.0);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, render_vertint);
    gl.vertexAttribPointer(0, render_vertint.itemSize, gl.FLOAT, false, 0, 0);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, render_texint);
    gl.vertexAttribPointer(1, render_texint.itemSize, gl.FLOAT, false, 0, 0);
    
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, rendertex);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, render_vertint.numItems);
    
    gl.flush();
   
  }
  
  function start()
  {
    var canvas = document.getElementById("myCanvas");
    canvas.width = 640;
    canvas.height = 480;
    
    cvWidth = canvas.width;
    cvHeight = canvas.height;
    
    var gl = init(canvas);
    setInterval(function() { Render(gl) }, 30);
  }
  
  function onMouseMove(e)
  {
    if (buttonFlg) {
      curAngleX += (window.scrollX + e.clientX - setX);
      curAngleY += (window.scrollY + e.clientY - setY);
      setX = window.scrollX + e.clientX;
      setY = window.scrollY + e.clientY;
    }
  }
  
  function onMouseDown(e)
  {
    setX = window.scrollX + e.clientX;
    setY = window.scrollY + e.clientY;
    buttonFlg = 1;
  }
  
  function onMouseUp(e)
  {
    buttonFlg = 0;
  }

  function onMouseWheel(e)
  {
    var delta = e.wheelDelta;
    if (delta > 0) {
      ++camLength;
    } else {
      --camLength;
    }
  }

  document.captureEvents(Event.MOUSEMOVE | Event.MOUSEDOWN | Event.MOUSEUP | Event.MOUSEWHEEL);
  document.onmousemove = onMouseMove;
  document.onmousedown = onMouseDown;
  document.onmouseup = onMouseUp;
  document.onmousewheel = onMouseWheel;
</script> 
</head> 
 
<body onload="start()"> 
<canvas id="myCanvas"> </canvas> 
</body> 
 
</html> 
